using AgCIM.Tools.Agm;
using AgCIM.Tools.Agm.Enums;
using AgCIM.Tools.Agm.Geometry;
using AgCIM.Tools.Agm.Material;
using AgCIM.Tools.IO.Shape;
using Newtonsoft.Json;
using System.Text;

namespace CarSimulate
{
    public partial class Form1 : Form
    {
        private System.Windows.Forms.Timer timer;
        private List<CarAgent> agents = new List<CarAgent>();
        private RoadManager roadManager = new RoadManager();

        public Form1()
        {
            InitializeComponent();
            CarAgent.RandomItem = new Random(System.Environment.TickCount);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.pictureBox1.Refresh();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            if (timer != null)
            {
                timer.Stop();
                timer.Dispose();
                timer = null;
                return;
            }
            else
            {
                timer = new System.Windows.Forms.Timer();
                timer.Interval = 100;
                timer.Tick += Timer_Tick;
                timer.Start();
            }
            for (var i = 0; i < agents.Count; i++)
            {
                var agent = agents[i];
                agent.Start();
            }
        }

        private void Timer_Tick(object? sender, EventArgs e)
        {
            for (var i = 0; i < agents.Count; i++)
            {
                var agent = agents[i];
                agent.MoveNext(agents);
            }
            for (var i = 0; i < agents.Count; i++)
            {
                var agent = agents[i];
                agent.WannaColl(agents);
            }
            StringBuilder sb = new StringBuilder();
            for (var i = 0; i < agents.Count; i++)
            {
                sb.AppendLine(agents[i].Id.ToString());
                var p1 = UnProject(agents[i].CarPos.CurrentPoint);
                sb.AppendLine(p1.X + "," + p1.Y.ToString());

                // 更新运动轨迹
                agents[i].UpdateTrajectory(UnProject(agents[i].CarPos.CurrentPoint));
            }
            this.textBox1.Text = sb.ToString();

            this.pictureBox1.Refresh();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.pictureBox1.Paint += PictureBox1_Paint;
        }

        private void PictureBox1_Paint(object? sender, PaintEventArgs e)
        {
            var g = e.Graphics;
            g.Clear(Color.White);

            for (var i = 0; i < agents.Count; i++)
            {
                var agent = agents[i];
                if (agent == null) return;
                g.DrawRectangle(Pens.Blue, agent.CarPos.CurrentPoint.X - 4, agent.CarPos.CurrentPoint.Y - 4, 8, 8);
                g.DrawString("粤" + agent.Id.ToString(), this.Font, Brushes.Red, agent.CarPos.CurrentPoint);
            }
            roadManager.Render(g, this.Font, this.checkBox1.Checked);
        }

        private GeographicBoundingBox m_shapeBoundingBox;
        private void button3_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "*.shp|*.shp";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                AgCIM.Tools.IO.Shape.ShapeDataGetterField sr = new AgCIM.Tools.IO.Shape.ShapeDataGetterField(ofd.FileName);
                roadManager.Clear();
                var bb = sr.SourceGeoBB;
                m_shapeBoundingBox = bb;
                for (var i = 0; i < sr.NumberRecords; i++)
                {
                    var item = sr.AllRecords[i].PolyLine;
                    AddLine(item, bb, sr.AllRecords[i].m_Attribute["RoadID"]);
                }
                this.pictureBox1.Refresh();

                roadManager.Initilize();
                this.pictureBox1.Refresh();
            }
        }

        private void AddLine(Shapefile_PolyLine item, GeographicBoundingBox bb, string roadId)
        {
            for (var i = 0; i < item.Points.Count; i++)
            {
                List<PointF> pts = new List<PointF>();
                for (var j = 0; j < item.Points[i].Count; j++)
                {
                    var p1 = this.ProjectCp(item.Points[i][j]);
                    pts.Add(p1);
                }
                for (var j = 0; j < pts.Count - 1; j++)
                {
                    var pt = pts[j];
                    var pt2 = pts[j + 1];
                    var lineId = int.Parse(roadId);
                    if (lineId == 0)
                    {
                        lineId = -1 * roadManager.AllLines.Count;
                    }
                    else
                    {

                    }
                    roadManager.AllLines.Add(new TrafficLine() { StartPoint = pt, EndPoint = pt2, LinePId = lineId });
                }
            }
        }
        private PointF ProjectCp(Shapefile_Point p)
        {
            var x1 = (p.X - m_shapeBoundingBox.MinX) / (m_shapeBoundingBox.MaxX - m_shapeBoundingBox.MinX) * (this.pictureBox1.Width - 20) / 1 + 10;
            var y1 = (p.Y - m_shapeBoundingBox.MinY) / (m_shapeBoundingBox.MaxY - m_shapeBoundingBox.MinY) * (this.pictureBox1.Height - 20) / 1 + 10;
            return new PointF((float)x1, (float)y1);
        }
        private Shapefile_Point UnProject(PointF p)
        {
            var x1 = (p.X - 10) * (m_shapeBoundingBox.MaxX - m_shapeBoundingBox.MinX) / (this.pictureBox1.Width - 20) + m_shapeBoundingBox.MinX;
            var y1 = (p.Y - 10) * (m_shapeBoundingBox.MaxY - m_shapeBoundingBox.MinY) / (this.pictureBox1.Height - 20) + m_shapeBoundingBox.MinY;
            return new Shapefile_Point((float)x1, (float)y1, 0);
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            this.pictureBox1.MouseClick += PictureBox1_MouseClick;
        }

        private void PictureBox1_MouseClick(object? sender, MouseEventArgs e)
        {
            CarAgent.RandomItem = new Random(System.Environment.TickCount);
            var agent4 = new CarAgent()
            {
                CarPos = new CarInLineStruct()
                {
                    CurrentPoint = new Point(e.Location.X, e.Location.Y),
                },
                Speed = CarAgent.RandomItem.Next(5, 15),
                Id = agents.Count
            };
            agents.Add(agent4);
            agent4.FindRoad(roadManager);
            this.pictureBox1.MouseClick -= PictureBox1_MouseClick;
            this.pictureBox1.Refresh();
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            this.pictureBox1.Refresh();
        }


        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            // 打开保存文件对话框
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "AGM文件 (*.agm)|*.agm|所有文件 (*.*)|*.*";
            saveFileDialog.DefaultExt = "agm";
            saveFileDialog.FileName = "carSimulate.agm";
            saveFileDialog.InitialDirectory = Application.StartupPath; // 设置默认保存路径为当前应用程序路径

            string savePath = "";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                savePath = saveFileDialog.FileName;
            }
            else
                return;
            SaveCarTrajectory(savePath);


        }
        private void SaveCarTrajectory(string savePath)
        {
            try
            {
                AgmModel agmModel = new AgmModel();
                agmModel.name = "汽车运动轨迹";
                agmModel.srs = AgmSrSType.WGS84.ToString();
                agmModel.entities = new List<AgmEntity>();
                agmModel.createTime = DateTime.Now.ToString();
                agmModel.encoding = "UTF8";
                for (int i = 0; i < agents.Count; i++)
                {
                    var agent = agents[i];

                    AgmLineString agmMultiPoint = new AgmLineString();
                    agmMultiPoint.srs = AgmSrSType.WGS84.ToString();
                    agmMultiPoint.path = new double[agent.MovementTrajectory.Count][];
                    for (global::System.Int32 j = 0; j < agmMultiPoint.path.Length; j++)
                    {
                        var p = agent.MovementTrajectory[j];
                        agmMultiPoint.path[j] = new double[3] { p.X, p.Y, 0 };
                    }

                    AgmEntity carEntity = new AgmEntity();
                    carEntity.name = "粤" + agent.Id.ToString();
                    carEntity.id = agent.Id.ToString();
                    carEntity.attributes = new Dictionary<string, dynamic>();
                    carEntity.attributes.Add("speed", agent.Speed);
                    carEntity.geometry = agmMultiPoint;

                    AgmLineSymbol lineSymbol = new AgmLineSymbol();
                    lineSymbol.width = 3;
                    lineSymbol.color = new double[4] { 0.8235, 0.8235, 0.1176, 1 };
                    lineSymbol.style = new AgmPolylineAnimation()
                    {
                        primitive = "http://112.94.31.72:1073/cesium/cim-resource-center/model3d/CesiumMan/Cesium_Man.glb",
                        direction = "alternate",
                        speed = agent.Speed,
                        scale = 10,
                        duration = 30,
                    };

                    carEntity.symbols = new List<AgCIM.Tools.Agm.Material.AgmSymbol>();
                    carEntity.symbols.Add(lineSymbol);
                    agmModel.entities.Add(carEntity);
                }

                File.WriteAllText(savePath, JsonConvert.SerializeObject(agmModel, new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore
                }));
                MessageBox.Show("保存成功！");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            MessageBox.Show("本软件是利用智能体来模拟车辆的行走。支持导出AGM模型。有陈彪、周慧云编写。");
        }
    }
}